Added support for Qstarz BL-1000 .BIN files (#515)
authorPierre Bernard <gloubibou@users.noreply.github.com>
Fri, 17 Apr 2020 12:17:18 +0000 (14:17 +0200)
committerGitHub <noreply@github.com>
Fri, 17 Apr 2020 12:17:18 +0000 (06:17 -0600)
* Added support for Qstarz BL-1000 .BIN files

* Use FormatSpecificData

* Updates based on pull request comments

* Remove executable bit on Qstarz sample file

* include-what-you-use headers

* Added format documentation for qstarz_bl_1000

Co-authored-by: gloubibou <pierre.bernard@web.de>
16 files changed:
CMakeLists.txt
GPSBabel.pro
Makefile.in
formspec.h
qstarz_bl_1000.cc [new file with mode: 0644]
qstarz_bl_1000.h [new file with mode: 0644]
reference/format0.txt
reference/format1.txt
reference/format2.txt
reference/format3.txt
reference/help.txt
reference/qstarz_bl-1000.BIN [new file with mode: 0644]
reference/qstarz_bl-1000.gpx [new file with mode: 0644]
testo.d/qstarz_bl_1000.test [new file with mode: 0644]
vecs.h
xmldoc/formats/qstarz_bl-1000.xml [new file with mode: 0644]

index 09c2923cd97d3720691a4954e3e4588d82130e5d..ec463faddf2efd8f76dcb1e8c619d56ee2681979 100644 (file)
@@ -53,7 +53,7 @@ set(ALL_FMTS
   vpl.cc teletype.cc jogmap.cc bushnell.cc bushnell_trl.cc wintec_tes.cc
   subrip.cc garmin_xt.cc garmin_fit.cc
   mtk_locus.cc googledir.cc mapbar_track.cc mapfactor.cc f90g_track.cc
-  energympro.cc mynav.cc ggv_bin.cc globalsat_sport.cc geojson.cc
+  energympro.cc mynav.cc ggv_bin.cc globalsat_sport.cc geojson.cc qstarz_bl_1000.cc
 )
 
 #DEPRECATED_FMTS=cetus.cc copilot.cc gpspilot.cc magnav.cc psp.cc gcdb.cc quovadis.cc gpilots.cc geoniche.cc palmdoc.cc hsa_ndv.cc coastexp.cc pathaway.cc coto.cc msroute.cc mag_pdb.cc axim_gpb.cc delbin.cc google.cc
index 9b162b63c8a5712c4508db2d34bec22716dafadc..3d69f75624fb4433905660d280befe06fc65725e 100644 (file)
@@ -46,7 +46,7 @@ ALL_FMTS=$$MINIMAL_FMTS gtm.cc gpsutil.cc pcx.cc \
         vpl.cc teletype.cc jogmap.cc bushnell.cc bushnell_trl.cc wintec_tes.cc \
         subrip.cc garmin_xt.cc garmin_fit.cc \
         mtk_locus.cc googledir.cc mapbar_track.cc mapfactor.cc f90g_track.cc \
-        energympro.cc mynav.cc ggv_bin.cc globalsat_sport.cc geojson.cc
+        energympro.cc mynav.cc ggv_bin.cc globalsat_sport.cc geojson.cc qstarz_bl_1000.cc
 
 DEPRECATED_FMTS=cetus.cc copilot.cc gpspilot.cc magnav.cc psp.cc gcdb.cc quovadis.cc gpilots.cc geoniche.cc palmdoc.cc hsa_ndv.cc coastexp.cc pathaway.cc coto.cc msroute.cc mag_pdb.cc axim_gpb.cc delbin.cc google.cc
 
index 1771cd8f45d4f0d61812bba031a08b0fb45d908b..a7053b6be1b09178bf6984a20c065b44c274d7c0 100644 (file)
@@ -85,7 +85,7 @@ ALL_FMTS=$(MINIMAL_FMTS) gtm.o gpsutil.o  \
        vpl.o teletype.o jogmap.o bushnell.o bushnell_trl.o wintec_tes.o \
        subrip.o garmin_xt.o garmin_fit.o \
        mtk_locus.o googledir.o mapbar_track.o f90g_track.o mapfactor.o energympro.o \
-       mynav.o ggv_bin.o globalsat_sport.o geojson.o
+       mynav.o ggv_bin.o globalsat_sport.o geojson.o qstarz_bl_1000.o
 
 FMTS=@FMTS@
 
@@ -922,6 +922,9 @@ position.o: position.cc defs.h config.h zlib/zlib.h zlib/zconf.h \
 psitrex.o: psitrex.cc defs.h config.h zlib/zlib.h zlib/zconf.h formspec.h \
   inifile.h gbfile.h session.h src/core/datetime.h src/core/optional.h \
   garmin_tables.h
+qstarz_bl_1000.o: qstarz_bl_1000.cc defs.h config.h zlib/zlib.h zlib/zconf.h \
+  formspec.h inifile.h gbfile.h session.h src/core/datetime.h \
+  src/core/optional.h format.h
 radius.o: radius.cc defs.h config.h zlib/zlib.h zlib/zconf.h formspec.h \
   inifile.h gbfile.h session.h src/core/datetime.h src/core/optional.h \
   radius.h filter.h grtcirc.h
index 075c54ab1f0fed6a5884b8161270c94a405e7b2e..7b26655294bd0784b7d62c5ddbba46cacf989d27 100644 (file)
@@ -31,6 +31,7 @@ enum FsType {
   kFsAn1V = 0x616e3176L,
   kFsOzi = 0x6f7a6900L,
   kFsGmsd = 0x474d5344L,       /* GMSD = Garmin specific data */
+  kFsQstarzBl1000 = 0x5173747aL,
   kFsLowranceusr4 = 0x615f234cL
 };
 
diff --git a/qstarz_bl_1000.cc b/qstarz_bl_1000.cc
new file mode 100644 (file)
index 0000000..b09ea1a
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+    Handle Qstarz BL-1000 .BIN files.
+
+    Saved in the SESSION/GPSLog folder. There will 3 files sharing the same base name: .BIN, .POI, and .DAT.
+    Only the .BIN file is of interest to us.
+
+    Copyright (C) 2020 Pierre Bernard, pierre.bernard@houdah.com
+    Copyright (C) 2001-2020 Robert Lipe, robertlipe+source@gpsbabel.org
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+ */
+
+#include "qstarz_bl_1000.h"
+
+#include <cmath>               // for round
+#include <QtCore/QChar>        // for QChar
+#include <QtCore/QDataStream>  // for QDataStream, QDataStream::SinglePrecision, QDataStream::DoublePrecision, QDataStream::LittleEndian, QDataStream::Ok
+#include <QtCore/QDebug>       // for QDebug
+#include <QtCore/QFile>        // for QFile
+#include <QtCore/QIODevice>    // for QIODevice, QIODevice::ReadOnly
+#include "defs.h"              // for Waypoint, ddmm2degrees, route_head, track_add_head, track_add_wpt, waypt_add, waypt_count, wp_flags, fix_unknown, fix_2d, fix_3d, fix_dgps, fix_none, fix_pps, fix_type, global_options, global_opts
+#include "src/core/logging.h"  // for Fatal
+
+
+#define MYNAME "Qstarz BL-1000"
+
+
+enum BL1000_POINT_TYPE {
+  BL1000_POINT_TYPE_UNKNOWN = '-',
+  BL1000_POINT_TYPE_WAY_POINT = 'B', // Button push
+  BL1000_POINT_TYPE_TRACK_POINT_BY_TIME = 'T',
+  BL1000_POINT_TYPE_TRACK_POINT_BY_DISTANCE = 'D',
+  BL1000_POINT_TYPE_TRACK_POINT_BY_SPEED = 'S',
+};
+
+
+/***************************************************************************
+ *           local helper functions                                        *
+ ***************************************************************************/
+
+inline bool qstarz_bl_1000_is_waypoint_type(BL1000_POINT_TYPE type)
+{
+  return (type == BL1000_POINT_TYPE_WAY_POINT);
+}
+
+inline bool qstarz_bl_1000_is_trackpoint_type(BL1000_POINT_TYPE type)
+{
+  return (
+           (type == BL1000_POINT_TYPE_TRACK_POINT_BY_TIME) ||
+           (type == BL1000_POINT_TYPE_TRACK_POINT_BY_DISTANCE) ||
+           (type == BL1000_POINT_TYPE_TRACK_POINT_BY_SPEED)
+         );
+}
+
+void
+QstarzBL1000Format::qstarz_bl_1000_read(QDataStream& stream)
+{
+  auto* track_route = new route_head;
+
+  track_add_head(track_route);
+
+  while (!stream.atEnd()) {
+    qstarz_bl_1000_read_record(stream, track_route);
+  }
+}
+
+void
+QstarzBL1000Format::qstarz_bl_1000_read_record(QDataStream& stream, route_head* track_route)
+{
+  // Value fields in 64-byte log entry
+  quint8                fixStatus;                // 0
+  qint8                 rcr;                      // 1
+  quint16               milliseconds;             // 2-3
+  double                dLatitude;                // 4-11
+  double                dLongitude;               // 12-19
+  quint32               time;                     // 20-23
+  float                 speed;                    // 24-27
+  float                 altitude;                 // 28-31
+  float                 heading;                  // 32-35
+  qint16                gx;                       // 36-37
+  qint16                gy;                       // 38-39
+  qint16                gz;                       // 40-41
+  quint16               maxSNR;                   // 42-43
+  float                 hdop;                     // 44-47
+  float                 vdop;                     // 48-51
+  qint8                 satelliteCountView;       // 52
+  qint8                 satelliteCountUsed;       // 53
+  quint8                fixQuality;               // 54
+  quint8               batteryPercent;           // 55
+  quint32               unused1;                  // 56-59
+  quint32               unused2;                  // 60-64
+
+  stream >> fixStatus;
+  stream >> rcr;
+  stream >> milliseconds;
+
+  stream.setFloatingPointPrecision(QDataStream::DoublePrecision);
+  stream >> dLatitude;
+  stream >> dLongitude;
+
+  stream >> time;
+
+  stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
+  stream >> speed;
+  stream >> altitude;
+  stream >> heading;
+
+  stream >> gx;
+  stream >> gy;
+  stream >> gz;
+  stream >> maxSNR;
+
+  stream.setFloatingPointPrecision(QDataStream::SinglePrecision);
+  stream >> hdop;
+  stream >> vdop;
+
+  stream >> satelliteCountView;
+  stream >> satelliteCountUsed;
+  stream >> fixQuality;
+  stream >> batteryPercent;
+  stream >> unused1;
+  stream >> unused2;
+
+  if (stream.status() != QDataStream::Ok) {
+    Fatal() << MYNAME << ": File format error on " << read_fname << ". Perhaps this isn't a Qstarz BL-1000 file";
+  }
+
+  BL1000_POINT_TYPE type;
+
+  switch (rcr) {
+  case 'B':
+    type = BL1000_POINT_TYPE_WAY_POINT;
+    break;
+  case 'T':
+    type = BL1000_POINT_TYPE_TRACK_POINT_BY_TIME;
+    break;
+  case 'D':
+    type = BL1000_POINT_TYPE_TRACK_POINT_BY_DISTANCE;
+    break;
+  case 'S':
+    type = BL1000_POINT_TYPE_TRACK_POINT_BY_SPEED;
+    break;
+  case 'W': // Power On
+  case 'X': // Power Off
+  case 'Y': // USB plug in
+  case 'Z': // USB removed
+  case 'C': // Cali G-sensor
+  case 'A': // Enter Smart Mode(Power Saving)
+  case 'R': // Reserved
+  case 'N': // Reserved
+  case 'M': // Reserved
+  case 'G': // Reserved
+  case 'H': // Reserved
+  case 'I': // Reserved
+  case 'J': // Reserved
+    type = BL1000_POINT_TYPE_UNKNOWN;
+    break;
+  default:
+    type = BL1000_POINT_TYPE_UNKNOWN;
+
+    Fatal() << MYNAME << ": File format error on " << read_fname << ". Unexpected value for RCR (record reason): " << rcr;
+
+    break;
+  }
+
+  fix_type fix;
+
+  switch (fixQuality) {
+  case 1:
+    switch (fixStatus) {
+    case 1:
+      fix = fix_none;
+      break;
+    case 2:
+      fix = fix_2d;
+      break;
+    case 3:
+      fix = fix_3d;
+      break;
+    default:
+      fix = fix_unknown;
+      break;
+    }
+    break;
+  case 2:
+    fix = fix_dgps;
+    break;
+  case 3:
+    fix = fix_pps;
+    break;
+  default:
+    fix = fix_unknown;
+
+    if (type != BL1000_POINT_TYPE_UNKNOWN) {
+      Fatal() << MYNAME << ": File format error on " << read_fname << ". Unexpected value for fix quality: " << fixQuality;
+    }
+
+    break;
+  }
+
+  auto* waypoint = new Waypoint();
+
+  waypoint->latitude = ddmm2degrees(dLatitude);
+  waypoint->longitude = ddmm2degrees(dLongitude);
+
+  // qDebug(waypoint)
+
+  if ((waypoint->latitude < -90) || (waypoint->latitude > 90)) {
+    Fatal() << MYNAME << ": File format error on " << read_fname << ". Unexpected value for latitude: " << waypoint->latitude;
+  }
+
+  if ((waypoint->longitude < -180) || (waypoint->longitude > 180)) {
+    Fatal() << MYNAME << ": File format error on " << read_fname << ". Unexpected value for longitude: " << waypoint->longitude;
+  }
+
+  waypoint->altitude = altitude;
+
+  waypoint->hdop = round(hdop * 1000) / 1000;
+  waypoint->vdop = round(vdop * 1000) / 1000;
+  waypoint->fix = fix;
+  waypoint->sat = satelliteCountUsed;
+
+  waypoint->speed = KPH_TO_MPS(speed);
+  waypoint->wpt_flags.speed = 1;
+
+  waypoint->course = heading;
+  waypoint->wpt_flags.course = 1;
+  waypoint->SetCreationTime(time, milliseconds);
+
+  auto* fsdata = new qstarz_bl_1000_fsdata;
+
+  waypoint->fs.FsChainAdd(fsdata);
+
+  fsdata->accelerationX = gx / 256.0;
+  fsdata->accelerationY = gy / 256.0;
+  fsdata->accelerationZ = gz / 256.0;
+
+  fsdata->satTotal = satelliteCountView;
+  fsdata->maxSNR = maxSNR;
+  fsdata->batteryPercent = batteryPercent;
+
+  if (qstarz_bl_1000_is_waypoint_type(type)) {
+    if (global_opts.synthesize_shortnames) {
+      waypoint->shortname = QString("WP%2").arg(waypt_count() + 1, 3, 10, QChar('0'));
+      waypoint->wpt_flags.shortname_is_synthetic = 1;
+    }
+    waypt_add(waypoint);
+  } else if (qstarz_bl_1000_is_trackpoint_type(type)) {
+    track_add_wpt(track_route, waypoint, "TP", 3);
+  } else {
+    delete waypoint;
+  }
+}
+
+
+/***************************************************************************
+ *              entry points called by gpsbabel main process               *
+ ***************************************************************************/
+
+void
+QstarzBL1000Format::rd_init(const QString& fname)
+{
+  read_fname = fname;
+}
+
+void
+QstarzBL1000Format::rd_deinit()
+{
+  read_fname.clear();
+}
+
+void
+QstarzBL1000Format::read()
+{
+  QFile file(read_fname);
+  if (!file.open(QIODevice::ReadOnly)) {
+    Fatal() << MYNAME << ": Error opening file " << read_fname;
+  }
+
+  QDataStream stream(&file);
+
+  stream.setByteOrder(QDataStream::LittleEndian);
+
+  qstarz_bl_1000_read(stream);
+
+  file.close();
+}
diff --git a/qstarz_bl_1000.h b/qstarz_bl_1000.h
new file mode 100644 (file)
index 0000000..67cb60d
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+    Handle Qstarz BL-1000 .BIN files.
+
+    Saved in the SESSION/GPSLog folder. There will 3 files sharing the same base name: .BIN, .POI, and .DAT.
+    Only the .BIN file is of interest to us.
+
+    Copyright (C) 2020 Pierre Bernard, pierre.bernard@houdah.com
+    Copyright (C) 2001-2020 Robert Lipe, robertlipe+source@gpsbabel.org
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+ */
+
+#ifndef QSTARZ_BL1000_H_INCLUDED_
+#define QSTARZ_BL1000_H_INCLUDED_
+
+#include <QtCore/QDataStream>  // for QDataStream
+#include <QtCore/QString>      // for QString
+#include <QtCore/QVector>      // for QVector
+#include <QtCore/QtGlobal>     // for qint8, quint16, quint8
+
+#include "defs.h"              // for ff_cap, ff_cap_read, ff_cap_none, CET_CHARSET_ASCII, ff_type, ff_type_file, route_head
+#include "format.h"            // for Format
+#include "formspec.h"          // for FormatSpecificData, kFsQstarzBl1000
+
+struct qstarz_bl_1000_fsdata : FormatSpecificData {
+  qstarz_bl_1000_fsdata() : FormatSpecificData(kFsQstarzBl1000) {}
+
+  qstarz_bl_1000_fsdata* clone() const override
+  {
+    return new qstarz_bl_1000_fsdata(*this);
+  }
+
+  char rcr; // record reason. possible values are listed in switch-case in .cc file
+  float accelerationX; // horizonal acceleration value measured in acceleration due to gravity or g
+  float accelerationY; // vertical acceleration value measured in acceleration due to gravity or g
+  float accelerationZ; // depth acceleration value measured in acceleration due to gravity or g
+  quint16 maxSNR;
+  qint8 satTotal; // satellite count (view)
+  quint8 batteryPercent;
+};
+
+class QstarzBL1000Format : public Format
+{
+public:
+  ff_type get_type() const override
+  {
+    return ff_type_file;
+  }
+
+  QVector<ff_cap> get_cap() const override
+  {
+    return {
+      ff_cap_read,  // waypoints
+      ff_cap_read,  // tracks
+      ff_cap_none   // routes
+    };
+  }
+
+  QString get_encode() const override
+  {
+    return CET_CHARSET_ASCII;
+  }
+
+  int get_fixed_encode() const override
+  {
+    return 0;
+  }
+
+  void rd_init(const QString& fname) override;
+  void read() override;
+  void rd_deinit() override;
+  void qstarz_bl_1000_read(QDataStream& stream);
+  void qstarz_bl_1000_read_record(QDataStream& stream, route_head* track_route);
+
+private:
+  QString read_fname;
+};
+
+
+#endif
index f86fce302552908deb7c03d4d789b321d60938f2..f3b196498a7acf8f2f52c41ceb75da6f243139ec 100644 (file)
@@ -126,6 +126,7 @@ ozi         OziExplorer
 pocketfms_bc           PocketFMS breadcrumbs
 pocketfms_fp   xml     PocketFMS flightplan (.xml)
 pocketfms_wp   txt     PocketFMS waypoints (.txt)
+qstarz_bl-1000         Qstarz BL-1000
 raymarine      rwf     Raymarine Waypoint File (.rwf)
 ricoh  log     Ricoh GPS Log File
 cup    cup     See You flight analysis data
index 88ae75533bc518f3d83a6d4d24fdd118971931aa..d63673b78d0083ceca9ec5137e4c5ad179197886 100644 (file)
@@ -130,6 +130,7 @@ file        ozi             OziExplorer
 file   pocketfms_bc            PocketFMS breadcrumbs
 file   pocketfms_fp    xml     PocketFMS flightplan (.xml)
 file   pocketfms_wp    txt     PocketFMS waypoints (.txt)
+file   qstarz_bl-1000          Qstarz BL-1000
 file   raymarine       rwf     Raymarine Waypoint File (.rwf)
 file   ricoh   log     Ricoh GPS Log File
 file   cup     cup     See You flight analysis data
index 0aaeaef97160353f492c9d963ce0cfd9fab49a7e..640c4e7e551f735c3245f2ab7c1f7263bf09ad0e 100644 (file)
@@ -130,6 +130,7 @@ file        rwrwrw  ozi             OziExplorer
 file   --rw--  pocketfms_bc            PocketFMS breadcrumbs
 file   r---r-  pocketfms_fp    xml     PocketFMS flightplan (.xml)
 file   rw----  pocketfms_wp    txt     PocketFMS waypoints (.txt)
+file   r-r---  qstarz_bl-1000          Qstarz BL-1000
 file   rw--rw  raymarine       rwf     Raymarine Waypoint File (.rwf)
 file   --rw--  ricoh   log     Ricoh GPS Log File
 file   rw----  cup     cup     See You flight analysis data
index 2e94d8ffc1d63c7d9727b5e40949911ad4d0cd04..7398ea5df2c3f6842d90c33e6cf69f856b48bf5c 100644 (file)
@@ -1196,6 +1196,8 @@ file      r---r-  pocketfms_fp    xml     PocketFMS flightplan (.xml)     pocketfms_fp
        https://www.gpsbabel.org/WEB_DOC_DIR/fmt_pocketfms_fp.html
 file   rw----  pocketfms_wp    txt     PocketFMS waypoints (.txt)      pocketfms_wp
        https://www.gpsbabel.org/WEB_DOC_DIR/fmt_pocketfms_wp.html
+file   r-r---  qstarz_bl-1000          Qstarz BL-1000  qstarz_bl-1000
+       https://www.gpsbabel.org/WEB_DOC_DIR/fmt_qstarz_bl-1000.html
 file   rw--rw  raymarine       rwf     Raymarine Waypoint File (.rwf)  raymarine
        https://www.gpsbabel.org/WEB_DOC_DIR/fmt_raymarine.html
 option raymarine       location        Default location        string  My Waypoints                    https://www.gpsbabel.org/WEB_DOC_DIR/fmt_raymarine.html#fmt_raymarine_o_location
index edd3bb9ddf37e27231f0c70983463e3170e0a3a7..b9b4c08c584223ead573c6170e16f48c7aeda564 100644 (file)
@@ -602,6 +602,7 @@ File Types (-i and -o options):
        pocketfms_bc          PocketFMS breadcrumbs
        pocketfms_fp          PocketFMS flightplan (.xml)
        pocketfms_wp          PocketFMS waypoints (.txt)
+       qstarz_bl-1000        Qstarz BL-1000
        raymarine             Raymarine Waypoint File (.rwf)
          location              Default location 
        ricoh                 Ricoh GPS Log File
diff --git a/reference/qstarz_bl-1000.BIN b/reference/qstarz_bl-1000.BIN
new file mode 100644 (file)
index 0000000..38d992c
Binary files /dev/null and b/reference/qstarz_bl-1000.BIN differ
diff --git a/reference/qstarz_bl-1000.gpx b/reference/qstarz_bl-1000.gpx
new file mode 100644 (file)
index 0000000..a698771
--- /dev/null
@@ -0,0 +1,472 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gpx version="1.0" creator="GPSBabel - https://www.gpsbabel.org" xmlns="http://www.topografix.com/GPX/1/0">
+  <time>1970-01-01T00:00:00Z</time>
+  <bounds minlat="25.067766267" minlon="121.591293783" maxlat="25.068748717" maxlon="121.592796933"/>
+  <wpt lat="25.068690117" lon="121.592073833">
+    <ele>8.092</ele>
+    <time>2020-02-19T01:25:08Z</time>
+    <name>WPT001</name>
+    <cmt>WPT001</cmt>
+    <desc>WPT001</desc>
+    <fix>3d</fix>
+    <sat>4</sat>
+    <hdop>0.660000</hdop>
+    <vdop>0.980000</vdop>
+  </wpt>
+  <wpt lat="25.068722683" lon="121.592244900">
+    <ele>17.455</ele>
+    <time>2020-02-19T01:25:16Z</time>
+    <name>WPT002</name>
+    <cmt>WPT002</cmt>
+    <desc>WPT002</desc>
+    <fix>3d</fix>
+    <sat>8</sat>
+    <hdop>1.450000</hdop>
+    <vdop>0.910000</vdop>
+  </wpt>
+  <wpt lat="25.068716800" lon="121.592409367">
+    <ele>21.537</ele>
+    <time>2020-02-19T01:25:28Z</time>
+    <name>WPT003</name>
+    <cmt>WPT003</cmt>
+    <desc>WPT003</desc>
+    <fix>3d</fix>
+    <sat>9</sat>
+    <hdop>1.110000</hdop>
+    <vdop>0.850000</vdop>
+  </wpt>
+  <wpt lat="25.068719650" lon="121.592491517">
+    <ele>25.720</ele>
+    <time>2020-02-19T01:25:32Z</time>
+    <name>WPT004</name>
+    <cmt>WPT004</cmt>
+    <desc>WPT004</desc>
+    <fix>3d</fix>
+    <sat>9</sat>
+    <hdop>1.110000</hdop>
+    <vdop>0.850000</vdop>
+  </wpt>
+  <wpt lat="25.068741317" lon="121.592633783">
+    <ele>33.871</ele>
+    <time>2020-02-19T01:25:39Z</time>
+    <name>WPT005</name>
+    <cmt>WPT005</cmt>
+    <desc>WPT005</desc>
+    <fix>3d</fix>
+    <sat>9</sat>
+    <hdop>1.110000</hdop>
+    <vdop>0.850000</vdop>
+  </wpt>
+  <wpt lat="25.068576050" lon="121.592748250">
+    <ele>39.305</ele>
+    <time>2020-02-19T01:26:01Z</time>
+    <name>WPT006</name>
+    <cmt>WPT006</cmt>
+    <desc>WPT006</desc>
+    <fix>3d</fix>
+    <sat>9</sat>
+    <hdop>1.110000</hdop>
+    <vdop>0.850000</vdop>
+  </wpt>
+  <wpt lat="25.068591733" lon="121.592583867">
+    <ele>38.290</ele>
+    <time>2020-02-19T01:26:11Z</time>
+    <name>WPT007</name>
+    <cmt>WPT007</cmt>
+    <desc>WPT007</desc>
+    <fix>3d</fix>
+    <sat>10</sat>
+    <hdop>1.010000</hdop>
+    <vdop>0.840000</vdop>
+  </wpt>
+  <wpt lat="25.068619717" lon="121.592520650">
+    <ele>39.093</ele>
+    <time>2020-02-19T01:26:15Z</time>
+    <name>WPT008</name>
+    <cmt>WPT008</cmt>
+    <desc>WPT008</desc>
+    <fix>3d</fix>
+    <sat>10</sat>
+    <hdop>1.010000</hdop>
+    <vdop>0.840000</vdop>
+  </wpt>
+  <wpt lat="25.068635300" lon="121.592396133">
+    <ele>40.247</ele>
+    <time>2020-02-19T01:26:22Z</time>
+    <name>WPT009</name>
+    <cmt>WPT009</cmt>
+    <desc>WPT009</desc>
+    <fix>3d</fix>
+    <sat>11</sat>
+    <hdop>0.910000</hdop>
+    <vdop>0.820000</vdop>
+  </wpt>
+  <wpt lat="25.068635000" lon="121.592197950">
+    <ele>36.111</ele>
+    <time>2020-02-19T01:26:34Z</time>
+    <name>WPT010</name>
+    <cmt>WPT010</cmt>
+    <desc>WPT010</desc>
+    <fix>3d</fix>
+    <sat>12</sat>
+    <hdop>0.850000</hdop>
+    <vdop>0.800000</vdop>
+  </wpt>
+  <wpt lat="25.068633367" lon="121.592121017">
+    <ele>35.846</ele>
+    <time>2020-02-19T01:26:40Z</time>
+    <name>WPT011</name>
+    <cmt>WPT011</cmt>
+    <desc>WPT011</desc>
+    <fix>3d</fix>
+    <sat>12</sat>
+    <hdop>0.860000</hdop>
+    <vdop>0.800000</vdop>
+  </wpt>
+  <wpt lat="25.068310867" lon="121.591895733">
+    <ele>33.704</ele>
+    <time>2020-02-19T01:27:17Z</time>
+    <name>WPT012</name>
+    <cmt>WPT012</cmt>
+    <desc>WPT012</desc>
+    <fix>3d</fix>
+    <sat>12</sat>
+    <hdop>0.860000</hdop>
+    <vdop>0.800000</vdop>
+  </wpt>
+  <wpt lat="25.068250817" lon="121.591895567">
+    <ele>32.540</ele>
+    <time>2020-02-19T01:27:23Z</time>
+    <name>WPT013</name>
+    <cmt>WPT013</cmt>
+    <desc>WPT013</desc>
+    <fix>3d</fix>
+    <sat>12</sat>
+    <hdop>0.860000</hdop>
+    <vdop>0.800000</vdop>
+  </wpt>
+  <trk>
+    <trkseg>
+      <trkpt lat="25.068724217" lon="121.592175767">
+        <ele>16.226</ele>
+        <time>2020-02-19T01:25:10Z</time>
+        <course>85.070000</course>
+        <speed>1.533044</speed>
+        <fix>3d</fix>
+        <sat>7</sat>
+        <hdop>1.660000</hdop>
+        <vdop>0.940000</vdop>
+      </trkpt>
+      <trkpt lat="25.068719300" lon="121.592279017">
+        <ele>18.556</ele>
+        <time>2020-02-19T01:25:19Z</time>
+        <course>94.059998</course>
+        <speed>1.095767</speed>
+        <fix>3d</fix>
+        <sat>8</sat>
+        <hdop>1.240000</hdop>
+        <vdop>0.860000</vdop>
+      </trkpt>
+      <trkpt lat="25.068718450" lon="121.592378533">
+        <ele>21.337</ele>
+        <time>2020-02-19T01:25:26Z</time>
+        <course>93.800003</course>
+        <speed>1.476456</speed>
+        <fix>3d</fix>
+        <sat>9</sat>
+        <hdop>1.110000</hdop>
+        <vdop>0.850000</vdop>
+      </trkpt>
+      <trkpt lat="25.068733517" lon="121.592596617">
+        <ele>32.409</ele>
+        <time>2020-02-19T01:25:37Z</time>
+        <course>95.839996</course>
+        <speed>1.394144</speed>
+        <fix>3d</fix>
+        <sat>9</sat>
+        <hdop>1.110000</hdop>
+        <vdop>0.850000</vdop>
+      </trkpt>
+      <trkpt lat="25.068748717" lon="121.592695933">
+        <ele>34.995</ele>
+        <time>2020-02-19T01:25:43Z</time>
+        <course>88.519997</course>
+        <speed>1.389000</speed>
+        <fix>3d</fix>
+        <sat>9</sat>
+        <hdop>1.110000</hdop>
+        <vdop>0.850000</vdop>
+      </trkpt>
+      <trkpt lat="25.068713983" lon="121.592780483">
+        <ele>36.327</ele>
+        <time>2020-02-19T01:25:50Z</time>
+        <course>156.889999</course>
+        <speed>1.352989</speed>
+        <fix>3d</fix>
+        <sat>9</sat>
+        <hdop>1.110000</hdop>
+        <vdop>0.850000</vdop>
+      </trkpt>
+      <trkpt lat="25.068618400" lon="121.592796933">
+        <ele>38.900</ele>
+        <time>2020-02-19T01:25:56Z</time>
+        <course>177.429993</course>
+        <speed>1.507322</speed>
+        <fix>3d</fix>
+        <sat>9</sat>
+        <hdop>1.110000</hdop>
+        <vdop>0.850000</vdop>
+      </trkpt>
+      <trkpt lat="25.068576400" lon="121.592715783">
+        <ele>38.710</ele>
+        <time>2020-02-19T01:26:03Z</time>
+        <course>267.480011</course>
+        <speed>1.275822</speed>
+        <fix>3d</fix>
+        <sat>9</sat>
+        <hdop>1.110000</hdop>
+        <vdop>0.850000</vdop>
+      </trkpt>
+      <trkpt lat="25.068580567" lon="121.592616733">
+        <ele>38.318</ele>
+        <time>2020-02-19T01:26:09Z</time>
+        <course>273.649994</course>
+        <speed>1.383856</speed>
+        <fix>3d</fix>
+        <sat>9</sat>
+        <hdop>1.110000</hdop>
+        <vdop>0.850000</vdop>
+      </trkpt>
+      <trkpt lat="25.068634067" lon="121.592416350">
+        <ele>40.410</ele>
+        <time>2020-02-19T01:26:21Z</time>
+        <course>273.959991</course>
+        <speed>1.414722</speed>
+        <fix>3d</fix>
+        <sat>11</sat>
+        <hdop>0.910000</hdop>
+        <vdop>0.820000</vdop>
+      </trkpt>
+      <trkpt lat="25.068633717" lon="121.592302667">
+        <ele>38.466</ele>
+        <time>2020-02-19T01:26:27Z</time>
+        <course>267.760010</course>
+        <speed>1.409578</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.068631217" lon="121.592091617">
+        <ele>35.997</ele>
+        <time>2020-02-19T01:26:42Z</time>
+        <course>270.010010</course>
+        <speed>1.342700</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.068634350" lon="121.591979617">
+        <ele>37.212</ele>
+        <time>2020-02-19T01:26:49Z</time>
+        <course>281.559998</course>
+        <speed>0.967156</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.068571433" lon="121.591917883">
+        <ele>34.867</ele>
+        <time>2020-02-19T01:26:58Z</time>
+        <course>214.130005</course>
+        <speed>1.275822</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.068471617" lon="121.591905467">
+        <ele>34.900</ele>
+        <time>2020-02-19T01:27:06Z</time>
+        <course>202.059998</course>
+        <speed>1.280967</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.068369067" lon="121.591883350">
+        <ele>34.622</ele>
+        <time>2020-02-19T01:27:12Z</time>
+        <course>188.479996</course>
+        <speed>1.157500</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.068280867" lon="121.591898483">
+        <ele>32.953</ele>
+        <time>2020-02-19T01:27:20Z</time>
+        <course>181.250000</course>
+        <speed>0.992878</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.068196600" lon="121.591858000">
+        <ele>31.464</ele>
+        <time>2020-02-19T01:27:29Z</time>
+        <course>176.839996</course>
+        <speed>1.193511</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.068103933" lon="121.591850117">
+        <ele>32.151</ele>
+        <time>2020-02-19T01:27:35Z</time>
+        <course>181.100006</course>
+        <speed>1.275822</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.068021083" lon="121.591807433">
+        <ele>30.846</ele>
+        <time>2020-02-19T01:27:43Z</time>
+        <course>179.210007</course>
+        <speed>1.399289</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.067953800" lon="121.591735383">
+        <ele>30.044</ele>
+        <time>2020-02-19T01:27:51Z</time>
+        <course>180.139999</course>
+        <speed>1.172933</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.067854500" lon="121.591744733">
+        <ele>27.201</ele>
+        <time>2020-02-19T01:28:00Z</time>
+        <course>185.139999</course>
+        <speed>1.440444</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.067766267" lon="121.591716267">
+        <ele>26.132</ele>
+        <time>2020-02-19T01:28:08Z</time>
+        <course>217.850006</course>
+        <speed>0.972300</speed>
+        <fix>3d</fix>
+        <sat>11</sat>
+        <hdop>0.940000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.067775067" lon="121.591609500">
+        <ele>25.763</ele>
+        <time>2020-02-19T01:28:16Z</time>
+        <course>283.320007</course>
+        <speed>1.301545</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.067802917" lon="121.591498883">
+        <ele>25.861</ele>
+        <time>2020-02-19T01:28:23Z</time>
+        <course>285.540009</course>
+        <speed>1.301545</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.067827400" lon="121.591394617">
+        <ele>27.001</ele>
+        <time>2020-02-19T01:28:30Z</time>
+        <course>289.260010</course>
+        <speed>1.352989</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.067852283" lon="121.591293783">
+        <ele>26.668</ele>
+        <time>2020-02-19T01:28:40Z</time>
+        <course>291.989990</course>
+        <speed>1.327267</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.067943367" lon="121.591317283">
+        <ele>23.075</ele>
+        <time>2020-02-19T01:28:47Z</time>
+        <course>22.600000</course>
+        <speed>1.301545</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.068022600" lon="121.591378883">
+        <ele>21.345</ele>
+        <time>2020-02-19T01:28:53Z</time>
+        <course>32.419998</course>
+        <speed>1.471311</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.068101633" lon="121.591450433">
+        <ele>18.598</ele>
+        <time>2020-02-19T01:29:00Z</time>
+        <course>44.570000</course>
+        <speed>1.172933</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.068162300" lon="121.591526817">
+        <ele>21.046</ele>
+        <time>2020-02-19T01:29:05Z</time>
+        <course>63.330002</course>
+        <speed>1.394144</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+      <trkpt lat="25.068210767" lon="121.591609750">
+        <ele>21.881</ele>
+        <time>2020-02-19T01:29:13Z</time>
+        <course>35.980000</course>
+        <speed>1.162645</speed>
+        <fix>3d</fix>
+        <sat>12</sat>
+        <hdop>0.860000</hdop>
+        <vdop>0.800000</vdop>
+      </trkpt>
+    </trkseg>
+  </trk>
+</gpx>
diff --git a/testo.d/qstarz_bl_1000.test b/testo.d/qstarz_bl_1000.test
new file mode 100644 (file)
index 0000000..b0e2ccc
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# qstarz_bl-1000 logger tests
+#
+FORMAT=qstarz_bl-1000
+
+rm -f ${TMPDIR}/$FORMAT.*
+
+gpsbabel -i $FORMAT -f ${REFERENCE}/$FORMAT.BIN -o gpx -F ${TMPDIR}/$FORMAT.gpx >/dev/null
+compare ${REFERENCE}/$FORMAT.gpx ${TMPDIR}/$FORMAT.gpx 
diff --git a/vecs.h b/vecs.h
index 7d033a840a9319ac1a1ff72ec81f2048d213ad5d..5c96ac1d82b07b7c31b3cadff341793c2f139fb7 100644 (file)
--- a/vecs.h
+++ b/vecs.h
@@ -35,7 +35,9 @@
 #include "legacyformat.h"
 #include "lowranceusr.h"
 #include "mynav.h"
+#include "qstarz_bl_1000.h"
 #include "nmea.h"
+#include "qstarz_bl_1000.h"
 #include "random.h"
 #include "shape.h"
 #include "xcsv.h"
@@ -409,6 +411,7 @@ private:
   GeoJsonFormat geojson_fmt;
   GgvBinFormat ggv_bin_fmt;
   LegacyFormat globalsat_sport_fmt {globalsat_sport_vecs};
+  QstarzBL1000Format qstarz_bl_1000_fmt;
 #endif // MAXIMAL_ENABLED
 
   const QVector<vecs_t> vec_list {
@@ -1313,6 +1316,13 @@ private:
       "GlobalSat GH625XT GPS training watch",
       nullptr,
       nullptr,
+    },
+    {
+      &qstarz_bl_1000_fmt,
+      "qstarz_bl-1000",
+      "Qstarz BL-1000",
+      nullptr,
+      nullptr,
     }
 #endif // MAXIMAL_ENABLED
   };
diff --git a/xmldoc/formats/qstarz_bl-1000.xml b/xmldoc/formats/qstarz_bl-1000.xml
new file mode 100644 (file)
index 0000000..97b6088
--- /dev/null
@@ -0,0 +1,7 @@
+<para>
+This format is used by the Qstarz BL-1000GT and BL-1000ST.
+</para>
+
+<para>
+These Qstarz devices are file based. GPS logs are saved as *.BIN files to the SESSION/GPSLog folder.
+</para>